clts();
setup_fpu(current);
+
+ /* Disable TS in guest CR0 unless the guest wants the exception too. */
__vmread_vcpu(v, CR0_READ_SHADOW, &cr0);
- if (!(cr0 & X86_CR0_TS)) {
+ if ( !(cr0 & X86_CR0_TS) )
+ {
__vmread_vcpu(v, GUEST_CR0, &cr0);
cr0 &= ~X86_CR0_TS;
__vmwrite(GUEST_CR0, cr0);
}
+
+ /* Xen itself doesn't need another exception. */
__vm_clear_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_NM);
}
*/
__vmread_vcpu(v, CR0_READ_SHADOW, &old_cr0);
paging_enabled = (old_cr0 & X86_CR0_PE) && (old_cr0 & X86_CR0_PG);
- /* If OS don't use clts to clear TS bit...*/
- if((old_cr0 & X86_CR0_TS) && !(value & X86_CR0_TS))
+
+ /*
+ * Disable TS? Then we do so at the same time, and initialise FPU.
+ * This avoids needing another vmexit.
+ */
+ if ( (old_cr0 & ~value & X86_CR0_TS) != 0 )
{
- clts();
- setup_fpu(v);
+ clts();
+ setup_fpu(v);
}
-
__vmwrite(GUEST_CR0, value | X86_CR0_PE | X86_CR0_PG | X86_CR0_NE);
__vmwrite(CR0_READ_SHADOW, value);
break;
case TYPE_CLTS:
TRACE_VMEXIT(1,TYPE_CLTS);
+
+ /* We initialise the FPU now, to avoid needing another vmexit. */
clts();
setup_fpu(current);
unsigned long cr0;
struct vcpu *v = current;
- __vmread_vcpu(v, GUEST_CR0, &cr0);
- if (!(cr0 & X86_CR0_TS)) {
+ /* FPU state already dirty? Then no need to setup_fpu() lazily. */
+ if ( test_bit(_VCPUF_fpu_dirtied, &v->vcpu_flags) )
+ return;
+
+ /*
+ * If the guest does not have TS enabled then we must cause and handle an
+ * exception on first use of the FPU. If the guest *does* have TS enabled
+ * then this is not necessary: no FPU activity can occur until the guest
+ * clears CR0.TS, and we will initialise the FPU when that happens.
+ */
+ __vmread_vcpu(v, CR0_READ_SHADOW, &cr0);
+ if ( !(cr0 & X86_CR0_TS) )
+ {
__vmwrite(GUEST_CR0, cr0 | X86_CR0_TS);
+ __vm_set_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_NM);
}
-
- __vmread_vcpu(v, CR0_READ_SHADOW, &cr0);
- if (!(cr0 & X86_CR0_TS))
- __vm_set_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_NM);
}
/* Works only for vcpu == current */